package com.lord.rowcopy.util;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Random;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;

import com.lord.rowcopy.common.constant.UploadPath;

import net.coobird.thumbnailator.Thumbnails;

/**
 * 文件操作工具类
 * @author Lord
 * @date 2018年1月10日
 */
public class FileUtil {

    /**
     * 根据类型获取上传基础路径，从枚举类获取
     * @param type 枚举类中的类型，如：101、203
     * @return
     */
    public static String getUploadPath(String type) {
        String dateStr = DateUtil.date2Str(new Date(), "/yyyyMM"); // 按日期分类文件夹，如：/201802
        try {
            UploadPath uploadPath = UploadPath.valueOf("PATH_" + type);
            String path = uploadPath.getPath();
            path = path + dateStr;
            return path;
        } catch (Exception e) {
            return UploadPath.DEFAULT.getPath() + dateStr;
        }
    }

    /**
     * 生成随机文件名称，不可能重复
     */
    public static String getRandomFileName() {
        Random r = new Random();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        StringBuffer sb = new StringBuffer();
        sb.append(sdf.format(new Date()));
        sb.append(UUID.randomUUID().toString().replace("-", "").substring(0, 8));
        sb.append(r.nextInt(1000));
        sb.append(r.nextInt(10000));
        return sb.toString();
    }

    /**
     * 得到文件的后缀名（文件类型）
     * @param fileName 文件路径或文件名称
     * @return 文件的后缀名，结果如：.txt .jpg
     */
    public static String getFileExt(String fileName) {
        String ext = "";
        if (fileName != null && (!"".equals(fileName))) {
            int index = fileName.lastIndexOf(".");
            if (index != -1) {
                ext = fileName.substring(index);
            }
        }
        return ext;
    }

    /**
     * 判断是否是图片文件
     * @param file 需要判断的文件
     * @return
     */
    public static boolean isImgFile(File file) {
        try {
            return isImgFile(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判断是否是图片文件
     * @param inputStream 输入文件流
     * @return
     */
    public static boolean isImgFile(InputStream inputStream) {
        try {
            BufferedImage image = ImageIO.read(inputStream);
            if (image == null || image.getWidth() == 0 || image.getHeight() == 0) {
                return false;
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 压缩图片大小，只压缩文件大小，宽高等全部不变
     * 如果传入的文件不是图片类型，则直接返回false
     * @param inputFile 输入文件
     * @param outFile 压缩后的图片文件
     * @return 压缩结果 true：成功，false：失败
     */
    public static boolean compressImg(File inputFile, File outFile) {
        if (!isImgFile(inputFile)) {
            return false;
        }
        /*
         * 使用的是谷歌的类库thumbnailator 其中的scale是可以指定图片的大小，值在0到1之间，1f就是原图大小，0.5就是原图的一半大小，这里的大小是指图片的长宽。
         * 而outputQuality是图片的质量，值也是在0到1，越接近于1质量越好，越接近于0质量越差
         */
        try {
            // 小于200KB的图片，不进行压缩
            long fileSize = inputFile.length() / 1024;
            if (fileSize <= 200) {
                FileUtils.copyFile(inputFile, outFile);
            } else {
                Thumbnails.of(inputFile).scale(1f).outputQuality(0.3f).toFile(outFile);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 压缩图片大小，只压缩文件大小，宽高等全部不变
     * 如果传入的文件不是图片类型，则直接返回false
     * @param inputFile 输入文件
     * @param outFile 压缩后的图片文件
     * @return 压缩结果 true：成功，false：失败
     */
    public static boolean compressImg(InputStream inputStream, File outFile) {
        /*
         * 使用的是谷歌的类库thumbnailator 其中的scale是可以指定图片的大小，值在0到1之间，1f就是原图大小，0.5就是原图的一半大小，这里的大小是指图片的长宽。
         * 而outputQuality是图片的质量，值也是在0到1，越接近于1质量越好，越接近于0质量越差
         */
        try {
            int fileSize = inputStream.available() / 1024;
            if (fileSize <= 200) {
                FileUtils.copyInputStreamToFile(inputStream, outFile);
            } else {
                Thumbnails.of(inputStream).scale(1f).outputQuality(0.3f).toFile(outFile);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除文件，如果file是文件夹，则用递归删除该文件夹及子文件夹下所有的文件
     * 这个方法将尽可能删除所有的文件，但是只要有一个文件没有被删除成功结果都会返回false
     * @param file 要删除的文件或文件夹
     * @return 目录下的所有文件都被成功删除时返回true，否则返回false
     */
    public static boolean deleteFile(File file) {
        if (file == null || (!file.exists())) {
            return false;
        }
        // 如果是具体的文件，而不是文件夹的话，直接删除
        if (file.isFile()) {
            file.delete();
        } else {
            // 如果是文件夹，递归继续删除
            File[] fileList = file.listFiles();
            if (fileList != null && fileList.length > 0) {
                for (File currFile : fileList) {
                    deleteFile(currFile);
                }
            }
            file.delete();
        }
        return true;
    }

    /**
     * 判断一个文件是否存在
     * 
     * @author zhanglun
     * @param file
     *            需要判断的文件或文件夹
     * @return 如果存在，返回true，否则返回false
     */
    public static boolean existsFile(File file) {
        if (file == null) {
            return false;
        }
        return file.exists();
    }

    /**
     * 判断一个文件是否存在
     * 
     * @author zhanglun
     * @param filePath
     *            完整的文件路径，如：E:/test/aa.txt
     * @return 如果存在，返回true，否则返回false
     */
    public static boolean existsFile(String filePath) {
        if (filePath == null || "".equals(filePath)) {
            return false;
        }
        return existsFile(new File(filePath));
    }

    /**
     * 创建文件夹，如果文件夹已存在，则直接跳出返回false，不进行创建
     * 
     * @author zhanglun
     * @param file
     *            要创建的文件夹
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createDirectory(File file) {
        return createDirectory(file, false);
    }

    /**
     * 创建文件夹
     * 
     * @author zhanglun
     * @param file
     *            要创建的文件夹
     * @param cover
     *            如果要创建的文件夹已存在，是否覆盖。 true：覆盖。将会删除原文件夹下所有的子文件
     *            false：不覆盖。直接跳出返回false，不进行创建
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createDirectory(File file, boolean cover) {
        if (file == null) {
            return false;
        }
        if (!existsFile(file)) {
            return file.mkdirs();
        } else {
            if (cover) {
                deleteFile(file);
                return file.mkdirs();
            } else {
                return false;
            }
        }
    }

    /**
     * 创建文件夹
     * 
     * @author zhanglun
     * @param filePath
     *            要创建的文件夹路径
     * @param cover
     *            如果要创建的文件夹已存在，是否覆盖。 true：覆盖。将会删除原文件夹下所有的子文件
     *            false：不覆盖。直接跳出返回false，不进行创建
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createDirectory(String filePath, boolean cover) {
        if (filePath == null || "".equals(filePath)) {
            return false;
        }
        filePath = filePath.replaceAll("\\\\", "/");
        return createDirectory(new File(filePath), cover);
    }

    /**
     * 创建文件夹，如果文件夹已存在，则直接跳出返回false，不进行创建
     * 
     * @author zhanglun
     * @param filePath
     *            要创建的文件夹路径
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createDirectory(String filePath) {
        return createDirectory(filePath, false);
    }

    /**
     * 创建单个文件，如果文件已存在，则直接跳出返回false，不进行创建
     * 
     * @author zhanglun
     * @param file
     *            要创建的文件
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createFile(File file) {
        return createFile(file, false);
    }

    /**
     * 创建单个文件
     * 
     * @author zhanglun
     * @param file
     *            要创建的文件
     * @param cover
     *            如果要创建的文件已存在，是否覆盖。true：覆盖，false：不覆盖
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createFile(File file, boolean cover) {
        if (file == null) {
            return false;
        }
        if (!existsFile(file)) {
            if (!file.getParentFile().exists()) {
                // 如果文件所在的目录不存在，则创建目录
                if (!createDirectory(file.getParentFile())) {
                    return false;
                }
            }
            // 创建文件
            try {
                return file.createNewFile();
            } catch (IOException e) {
                return false;
            }
        } else {
            if (cover) {
                deleteFile(file);
                try {
                    return file.createNewFile();
                } catch (IOException e) {
                    return false;
                }
            } else {
                return false;
            }
        }
    }

    /**
     * 创建单个文件，如果文件已存在，则直接跳出返回false，不进行创建
     * 
     * @author zhanglun
     * @param fileName
     *            要创建的文件全路径，如：D:/aa/bb.txt
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createFile(String fileName) {
        return createFile(fileName, false);
    }

    /**
     * 创建单个文件
     * 
     * @author zhanglun
     * @param fileName
     *            要创建的文件全路径，如：D:/aa/bb.txt
     * @param cover
     *            如果要创建的文件已存在，是否覆盖。true：覆盖，false：不覆盖
     * @return 如果创建成功，则返回true，否则返回false
     */
    public static boolean createFile(String fileName, boolean cover) {
        if (fileName == null || "".equals(fileName)) {
            return false;
        }
        fileName = fileName.replaceAll("\\\\", "/");
        return createFile(new File(fileName), cover);
    }

    /**
     * 上传文件
     * 
     * @author zhanglun
     * @param file
     *            要保存的源文件
     * @param destFile
     *            保存的目标路径
     * @return
     */
    public static boolean saveFile(File file, String destFile) {
        try {
            destFile = destFile.replaceAll("\\\\", "/");
            if (destFile.lastIndexOf(".") == -1 || destFile.lastIndexOf("/") == -1) {
                return false;
            }
            // 如果不存在该文件夹，就创建
            String tempOutFile = destFile.substring(0, destFile.lastIndexOf("/"));
            if (!new File(tempOutFile).exists()) {
                new File(tempOutFile).mkdirs();
            }

            // 获得上传对象的输入流
            InputStream inputStream = new FileInputStream(file);

            if (inputStream != null) {
                // 建立文件输出流
                OutputStream outputStream = new FileOutputStream(destFile);

                // 建立缓冲区
                byte[] bs = new byte[1024];
                int count = 0;
                // 从输入流中读出数据放入缓冲区中,并给count赋予写入缓冲区的总字节数,如果count大于0，就说明还有数据，则继续写入。
                while ((count = inputStream.read(bs)) > 0) {
                    // 将缓冲区数据写入文件，每次写入的长度为count字节
                    outputStream.write(bs, 0, count);
                }
                // 关闭输入流
                inputStream.close();
                // 关闭文件输出流
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获得图片大小
     * 
     * @param path
     *            图片路径
     */
    public static long getPicSize(String path) {
        File file = new File(path);
        return file.length();
    }

    /**
     * 根据给定的文件路径读取文件内容
     * 
     * @param filePath
     *            文件全路径
     * @return 读取到的内容
     */
    public static String read(String filePath) {
        if (filePath == null || filePath == "") {
            return null;
        }
        if (filePath.lastIndexOf(".") == -1) {
            return null;
        }
        InputStream is = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return null;
            }
            is = new FileInputStream(file);
            byte buffer[] = new byte[1024];
            int len = 0;
            StringBuffer result = new StringBuffer();
            while ((len = is.read(buffer, 0, buffer.length)) > 0) {
                result.append(new String(buffer, 0, len));
            }
            return result.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }
    }

    /**
     * 把内容写到相应的文件中
     * 
     * @param conent
     *            要写的文件内容
     * @param filePath
     *            文件路径
     */
    public static boolean write(String content, String filePath) {
        if (filePath == null || filePath == "") {
            return false;
        }
        filePath = filePath.replaceAll("\\\\", "/");
        if (filePath.lastIndexOf(".") == -1 || filePath.lastIndexOf("/") == -1) {
            return false;
        }

        String folder = filePath.substring(0, filePath.lastIndexOf("/"));
        File file = new File(folder);
        if (!file.exists()) {
            file.mkdirs();
        }
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath)));
            bw.write(content);
            bw.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            }
        }
    }

    /**
     * 压缩图片
     * 
     * @param inputFile
     *            源图片
     * @param outFile
     *            处理后图片
     * @param width
     *            宽度
     * @param height
     *            高度
     * @param proportion
     *            是否等比缩放
     */
    public static boolean compressPic(String inputFile, String outFile, int width, int height, boolean proportion) {
        try {
            // 获得源文件
            File file = new File(inputFile);
            if (!file.exists()) {
                return false;
            }
            Image img = ImageIO.read(file);
            // 判断图片格式是否正确
            if (img.getWidth(null) == -1) {
                return false;
            } else {
                int newWidth;
                int newHeight;
                // 判断是否是等比缩放
                if (proportion == true) {
                    // 为等比缩放计算输出的图片宽度及高度
                    double rate1 = ((double) img.getWidth(null)) / (double) width + 0.1;
                    double rate2 = ((double) img.getHeight(null)) / (double) height + 0.1;
                    // 根据缩放比率大的进行缩放控制
                    double rate = rate1 > rate2 ? rate1 : rate2;
                    newWidth = (int) ((img.getWidth(null)) / rate);
                    newHeight = (int) ((img.getHeight(null)) / rate);
                } else {
                    newWidth = width; // 输出的图片宽度
                    newHeight = height; // 输出的图片高度
                }
                // 如果图片小于目标图片的宽和高则不进行转换
                if (img.getWidth(null) < width && img.getHeight(null) < height) {
                    newWidth = img.getWidth(null);
                    newHeight = img.getHeight(null);
                }
                BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);

                // Image.SCALE_SMOOTH 的缩略算法生成缩略图片的平滑度的,优先级比速度高生成的图片质量比较好但速度慢
                tag.getGraphics().drawImage(img.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);
                FileOutputStream out = new FileOutputStream(outFile);
                // JPEGImageEncoder可适用于其他图片类型的转换
                // JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                // encoder.encode(tag);
                out.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return true;
    }

    /**
     * 裁剪图片
     * 
     * @param srcFile
     *            源图片
     * @param outFile
     *            产生新图片路径
     * @param x
     *            x轴的开始坐标
     * @param y
     *            y轴的开始坐标
     * @param width
     *            所裁剪的宽度
     * @param height
     *            所裁剪的高度
     */
    public static boolean cutPic(String srcFile, String outFile, int x, int y, int width, int height) {
        FileInputStream is = null;
        ImageInputStream iis = null;
        try {
            // 如果源图片不存在
            if (!new File(srcFile).exists()) {
                return false;
            }

            // 读取图片文件
            is = new FileInputStream(srcFile);
            // 获取文件格式
            String ext = srcFile.substring(srcFile.lastIndexOf(".") + 1);

            // ImageReader声称能够解码指定格式
            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext);
            ImageReader reader = it.next();

            // 获取图片流
            iis = ImageIO.createImageInputStream(is);
            // 输入源中的图像将只按顺序读取
            reader.setInput(iis, true);
            // 描述如何对流进行解码
            ImageReadParam param = reader.getDefaultReadParam();
            // 图片裁剪区域
            Rectangle rect = new Rectangle(x, y, width, height);
            // 提供一个 BufferedImage，将其用作解码像素数据的目标
            param.setSourceRegion(rect);
            // 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象
            BufferedImage bi = reader.read(0, param);
            // 保存新图片
            File tempOutFile = new File(outFile);
            if (!tempOutFile.exists()) {
                tempOutFile.mkdirs();
            }
            ImageIO.write(bi, ext, new File(outFile));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (iis != null) {
                    iis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        }

    }

    public static boolean moveFile(File srcFile, String descFilePath, boolean cover) {
        copyFile(srcFile, descFilePath, cover);
        deleteFile(srcFile);
        return true;
    }

    /**
     * 复制单个文件或整个文件夹
     * 
     * @author zhanglun
     * @param srcFile
     *            需要拷贝的源文件
     * @param descFile
     *            目标文件路径
     * @param cover
     *            如果目标文件已存在，是否覆盖。true：覆盖，false：不覆盖
     * @return 如果复制成功，则返回true，否则返回false
     */
    public static boolean copyFile(File srcFile, String descFilePath, boolean cover) {
        if (!srcFile.exists()) {
            return false;
        }
        if (descFilePath == null || (!"".equals(descFilePath))) {
            return false;
        }
        // 如果目标文件夹名不以文件分隔符结尾，自动添加文件分隔符
        if (!descFilePath.endsWith(File.separator)) {
            descFilePath = descFilePath + File.separator;
        }
        File descFile = new File(descFilePath);
        if (descFile.exists()) {
            if (cover) {
                deleteFile(descFile);
            } else {
                return false;
            }
        } else {
            if (!descFile.getParentFile().exists()) {
                if (!descFile.getParentFile().mkdirs()) {
                    return false;
                }
            }
        }

        // 如果是具体的文件，而不是文件夹的话，直接复制
        if (srcFile.isFile()) {
            // 准备复制文件
            int readByte = 0;
            InputStream is = null;
            OutputStream os = null;
            try {
                is = new FileInputStream(srcFile);
                os = new FileOutputStream(descFile);
                byte[] buf = new byte[1024];
                // 一次读取1024个字节，当readByte为-1时表示文件已经读取完毕
                while ((readByte = is.read(buf)) != -1) {
                    // 将读取的字节流写入到输出流
                    os.write(buf, 0, readByte);
                }
                return true;
            } catch (Exception e) {
                return false;
            } finally {
                try {
                    // 关闭输入输出流，首先关闭输出流，然后再关闭输入流
                    if (os != null) {
                        os.flush();
                        os.close();
                    }
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    return false;
                }
            }
        } else {
            // 如果是文件夹，递归复制每一个子文件
            File[] fileList = srcFile.listFiles();
            if (fileList != null && fileList.length > 0) {
                for (File currFile : fileList) {
                    copyFile(currFile, descFilePath + currFile.getName(), cover);
                }
            }
        }
        return true;
    }

    /**
     * 压缩文件或目录
     * 
     * @author zhanglun
     * @param srcFile
     *            需要压缩的源文件，可以是单个文件或文件夹
     * @param descFileName
     *            目标zip文件（完整路径加ZIP文件名称）
     * @param cover
     *            如果目标文件已存在，是否覆盖。true：覆盖，false：不覆盖
     */
    public static boolean zipFile(File srcFile, String descZipFileName, boolean cover) {
        if (!srcFile.exists()) {
            return false;
        }
        if (descZipFileName == null || (!"".equals(descZipFileName))) {
            return false;
        }
        File descFile = new File(descZipFileName);
        if (descFile.exists()) {
            if (cover) {
                deleteFile(descFile);
            } else {
                return false;
            }
        } else {
            if (!descFile.getParentFile().exists()) {
                if (!descFile.getParentFile().mkdirs()) {
                    return false;
                }
            }
        }

        if (srcFile.isFile()) {
            FileInputStream fis = null;
            ZipEntry entry = null;
            ZipOutputStream zos = null;
            byte[] buf = new byte[4096];
            int readByte = 0;

            try {
                // 创建一个文件输入流
                fis = new FileInputStream(srcFile);
                // 创建一个ZipEntry
                entry = new ZipEntry(descZipFileName);

                zos = new ZipOutputStream(new FileOutputStream(descZipFileName));
                // 存储信息到压缩文件
                zos.putNextEntry(entry);
                // 复制字节到压缩文件
                while ((readByte = fis.read(buf)) != -1) {
                    zos.write(buf, 0, readByte);
                }
            } catch (Exception e) {
                return false;
            } finally {
                try {
                    if (zos != null) {
                        zos.closeEntry();
                        zos.flush();
                        zos.close();
                    }
                    if (fis != null) {
                        fis.close();
                    }
                } catch (IOException e) {
                    return false;
                }
            }
        } else {
            // 如果是文件夹，递归复制每一个子文件
            File[] fileList = srcFile.listFiles();
            if (fileList != null && fileList.length > 0) {
                for (File currFile : fileList) {
                    zipFile(currFile, descZipFileName + currFile.getName(), cover);
                }
            }
        }
        return true;
    }

    /**
     * 功能描述：解压缩ZIP文件，将ZIP文件里的内容解压到descFileName目录下
     * 
     * @param zipFileName
     *            需要解压的ZIP文件
     * @param descFileName
     *            目标文件
     */
    @SuppressWarnings({ "rawtypes", "resource" })
    public static void unZipFiles(String zipFileName, String descFileName) {
        if (!descFileName.endsWith(File.separator)) {
            descFileName = descFileName + File.separator;
        }
        try {
            // 根据ZIP文件创建ZipFile对象
            ZipFile zipFile = new ZipFile(zipFileName);
            ZipEntry entry = null;
            String entryName = null;
            String descFileDir = null;
            byte[] buf = new byte[4096];
            int readByte = 0;
            // 获取ZIP文件里所有的entry
            Enumeration enums = zipFile.entries();
            // 遍历所有entry
            while (enums.hasMoreElements()) {
                entry = (ZipEntry) enums.nextElement();
                // 获得entry的名字
                entryName = entry.getName();
                descFileDir = descFileName + entryName;
                if (entry.isDirectory()) {
                    // 如果entry是一个目录，则创建目录
                    new File(descFileDir).mkdirs();
                    continue;
                } else {
                    // 如果entry是一个文件，则创建父目录
                    new File(descFileDir).getParentFile().mkdirs();
                }
                File file = new File(descFileDir);
                // 打开文件输出流
                FileOutputStream fouts = new FileOutputStream(file);
                // 从ZipFile对象中打开entry的输入流
                InputStream ins = zipFile.getInputStream(entry);
                while ((readByte = ins.read(buf)) != -1) {
                    fouts.write(buf, 0, readByte);
                }
                fouts.close();
                ins.close();
            }
            System.out.println("文件解压成功!");
        } catch (Exception e) {
            System.out.println("文件解压失败：" + e.getMessage());
        }
    }

    /**
     * 这个方法可以通过与某个类的class文件的相对路径来获取文件或目录的绝对路径。 通过这个方法，可以根据程序自身的类文件的位置来定位某个相对路径。
     * 比如：某个txt文件相对于程序的Test类文件的路径是../../resource/test.txt，
     * 那么使用本方法Path.getFullPathRelateClass("../../resource/test.txt",Test.class)
     * 得到的结果是txt文件的在系统中的绝对路径。
     * 
     * @param relatedPath
     *            相对路径
     * @param cls
     *            用来定位的类
     * @return 相对路径所对应的绝对路径
     * @throws IOException
     */
    @SuppressWarnings("rawtypes")
    public static String getFullPathRelatedClass(String relatedPath, Class cls) throws IOException {
        String path = null;
        if (relatedPath == null) {
            throw new NullPointerException();
        }
        String clsPath = getPathFromClass(cls);
        File clsFile = new File(clsPath);
        String tempPath = clsFile.getParent() + File.separator + relatedPath;
        File file = new File(tempPath);
        path = file.getCanonicalPath();
        path = java.net.URLDecoder.decode(path, "UTF-8");
        return path;
    }

    /**
     * 获取一个类的class文件所在的绝对路径 只要是在本程序中可以被加载的类，都可以定位到它的class文件的绝对路径。
     * 
     * @param cls
     *            一个对象的Class属性
     * @return 这个类的class文件位置的绝对路径。 如果没有这个类的定义，则返回null。
     */
    @SuppressWarnings("rawtypes")
    public static String getPathFromClass(Class cls) throws IOException {
        String path = null;
        if (cls == null) {
            throw new NullPointerException();
        }
        URL url = getClassLocationURL(cls);
        if (url != null) {
            path = url.getPath();
            if ("jar".equalsIgnoreCase(url.getProtocol())) {
                try {
                    path = new URL(path).getPath();
                } catch (MalformedURLException e) {
                }
                int location = path.indexOf("!/");
                if (location != -1) {
                    path = path.substring(0, location);
                }
            }
            File file = new File(path);
            path = file.getCanonicalPath();
            path = java.net.URLDecoder.decode(path, "UTF-8");
        }
        return path;
    }

    /**
     * 获取类的class文件位置的URL。这个方法是本类最基础的方法，供其它方法调用。
     */
    @SuppressWarnings("rawtypes")
    private static URL getClassLocationURL(Class cls) {
        if (cls == null)
            throw new IllegalArgumentException("输入的参数类为null!");
        URL result = null;
        final String clsAsResource = cls.getName().replace('.', '/').concat(".class");
        final ProtectionDomain pd = cls.getProtectionDomain();
        if (pd != null) {
            final CodeSource cs = pd.getCodeSource();
            if (cs != null)
                result = cs.getLocation();
            if (result != null) {
                if ("file".equals(result.getProtocol())) {
                    try {
                        if (result.toExternalForm().endsWith(".jar") || result.toExternalForm().endsWith(".zip"))
                            result = new URL("jar:".concat(result.toExternalForm()).concat("!/").concat(clsAsResource));
                        else if (new File(result.getFile()).isDirectory())
                            result = new URL(result, clsAsResource);
                    } catch (MalformedURLException ignore) {
                    }
                }
            }
        }
        if (result == null) {
            final ClassLoader clsLoader = cls.getClassLoader();
            result = clsLoader != null ? clsLoader.getResource(clsAsResource)
                    : ClassLoader.getSystemResource(clsAsResource);
        }
        return result;
    }

    /**
     * 读取文本文件内容
     * 
     * @param filePathAndName
     *            带有完整绝对路径的文件名
     * @param encoding
     *            文本文件打开的编码方式
     * @return 返回文本文件的内容
     */
    @SuppressWarnings("resource")
    public String readTxt(String filePathAndName, String encoding) throws IOException {
        encoding = encoding.trim();
        StringBuffer str = new StringBuffer("");
        String st = "";
        try {
            FileInputStream fs = new FileInputStream(filePathAndName);
            InputStreamReader isr;
            if (encoding.equals("")) {
                isr = new InputStreamReader(fs);
            } else {
                isr = new InputStreamReader(fs, encoding);
            }
            BufferedReader br = new BufferedReader(isr);
            try {
                String data = "";
                while ((data = br.readLine()) != null) {
                    str.append(data + " ");
                }
            } catch (Exception e) {
                str.append(e.toString());
            }
            st = str.toString();
        } catch (IOException es) {
            st = "";
        }
        return st;
    }

    /**
     * 获取文件夹根目录
     * @return
     */
    public static String getFileFolderPath(HttpServletRequest request) {
        if (null != request) {
            String serverPath = request.getSession().getServletContext().getRealPath("/");
            String contextPath = request.getSession().getServletContext().getContextPath();
            serverPath = serverPath.replace(contextPath.substring(1), contextPath.substring(1) + "_upload");
            return serverPath;
        }
        return "";
    }

    /**
     * 获取根目录文件夹下的文件目录
     * @return
     */
    public static String getFilePath() {
        return "/upload/" + DateUtil.date2Str(new Date(), "yyyyMM/");
    }

    /**
     * 获取根目录文件夹下的文件目录
     * @return
     */
    public static String getFilePathForCert() {
        return "/certs/";
    }

    /**
     * 下载远程文件到本地
     * @param remoteFilePath 远程文件完整路径 如：https://timgsa.baidu.com/timg?im5714.jpg
     * @param localFilePath 本地存储路径，不包含文件名称，如：d:/file/upload 即可
     * @return
     */
    public static File downloadFile(String remoteFilePath, String localFilePath) {
        URL urlfile = null;
        HttpURLConnection httpUrl = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        String extName = remoteFilePath.substring(remoteFilePath.lastIndexOf("."));
        String fileName = FileUtil.getRandomFileName() + extName;
        File f = new File(localFilePath + "/" + fileName);
        try {
            urlfile = new URL(remoteFilePath);
            httpUrl = (HttpURLConnection) urlfile.openConnection();
            httpUrl.connect();
            bis = new BufferedInputStream(httpUrl.getInputStream());
            bos = new BufferedOutputStream(new FileOutputStream(f));
            int len = 2048;
            byte[] b = new byte[len];
            while ((len = bis.read(b)) != -1) {
                bos.write(b, 0, len);
            }
            bos.flush();
            bis.close();
            httpUrl.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return f;
    }

}
